package xyz.ssf.cloud.common.core.storage;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import xyz.ssf.cloud.common.config.StorageConfig;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 存储工厂类
 * 用于获取当前配置的存储策略
 * 
 * @author ssf
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class StorageFactory {
    
    private final StorageConfig storageConfig;
    private final List<StorageStrategy> strategies;
    private final Map<String, StorageStrategy> strategyMap = new ConcurrentHashMap<>();
    
    /**
     * 存储类型配置
     */
    @Value("${storage.type:local}")
    private String storageType;
    
    /**
     * 所有存储策略的实现
     * key: 策略类型名称
     * value: 策略实现
     */
    @Autowired
    private Map<String, StorageStrategy> storageStrategies;
    
    /**
     * 获取当前配置的存储策略
     * 
     * @return 存储策略
     */
    public StorageStrategy getStorageStrategy() {
        // 从所有实现中获取当前配置的存储策略
        StorageStrategy strategy = storageStrategies.get(storageType + "StorageStrategy");
        
        // 如果没有找到，返回默认的本地存储策略
        if (strategy == null) {
            strategy = storageStrategies.get("localStorageStrategy");
        }
        
        return strategy;
    }
    
    /**
     * 获取指定类型的存储策略
     * 
     * @param type 存储类型
     * @return 存储策略
     */
    public StorageStrategy getStorageStrategy(String type) {
        return storageStrategies.get(type + "StorageStrategy");
    }
    
    /**
     * 获取所有可用的存储策略类型
     */
    public Map<String, String> getAvailableTypes() {
        Map<String, String> types = new ConcurrentHashMap<>();
        
        // 初始化存储策略
        if (strategyMap.isEmpty()) {
            for (StorageStrategy strategy : strategies) {
                strategyMap.put(strategy.getType(), strategy);
            }
        }
        
        // 遍历所有存储类型
        for (StorageType type : StorageType.values()) {
            if (strategyMap.containsKey(type.getCode())) {
                types.put(type.getCode(), type.getName());
            }
        }
        
        return types;
    }
    
    /**
     * 本地存储策略实现
     * 作为内部类集成到StorageFactory中
     */
    @Slf4j
    @Component("localStorageStrategy")
    @RequiredArgsConstructor
    public static class LocalStorageStrategy implements StorageStrategy {
        
        private final StorageConfig storageConfig;
        
        @Override
        public String uploadFile(MultipartFile file, String path, String filename) throws Exception {
            InputStream inputStream = file.getInputStream();
            return uploadFile(inputStream, path, filename);
        }
        
        @Override
        public String uploadFile(InputStream inputStream, String path, String filename) throws Exception {
            String storagePath = storageConfig.getLocal().getStoragePath();
            if (!StringUtils.hasText(path)) {
                path = "";
            }
            
            String uploadPath = storagePath + File.separator + path;
            
            // 创建目录
            File directory = new File(uploadPath);
            if (!directory.exists()) {
                directory.mkdirs();
            }
            
            // 写入文件
            String filePath = uploadPath + File.separator + filename;
            File destFile = new File(filePath);
            
            try (FileOutputStream outputStream = new FileOutputStream(destFile)) {
                IOUtils.copy(inputStream, outputStream);
            } finally {
                inputStream.close();
            }
            
            // 返回文件访问URL
            String domain = storageConfig.getLocal().getDomain();
            String accessPath = storageConfig.getLocal().getAccessPath();
            
            // 处理路径格式
            String fileUrl;
            
            // 处理域名格式
            if (StringUtils.hasText(domain)) {
                // 确保域名有正确的协议前缀
                if (!domain.startsWith("http://") && !domain.startsWith("https://")) {
                    domain = "http://" + domain;
                }
                // 确保域名结尾没有斜杠
                if (domain.endsWith("/")) {
                    domain = domain.substring(0, domain.length() - 1);
                }
            } else {
                // 未配置域名，使用默认的localhost
                domain = "http://localhost:8080";
            }
            
            // 确保访问路径以斜杠开头
            if (!accessPath.startsWith("/")) {
                accessPath = "/" + accessPath;
            }
            
            // 构建完整的URL (带域名)
            fileUrl = domain + accessPath;
            
            // 处理路径中间部分，移除多余的斜杠
            if (fileUrl.endsWith("/")) {
                fileUrl = fileUrl.substring(0, fileUrl.length() - 1);
            }
            
            // 添加子目录
            if (StringUtils.hasText(path)) {
                if (!path.startsWith("/")) {
                    fileUrl += "/";
                }
                if (path.endsWith("/")) {
                    path = path.substring(0, path.length() - 1);
                }
                fileUrl += path;
            }
            
            // 添加文件名
            fileUrl += "/" + filename;
            
            log.info("生成本地存储文件URL: {}", fileUrl);
            return fileUrl;
        }
        
        @Override
        public boolean deleteFile(String fileUrl) throws Exception {
            if (!StringUtils.hasText(fileUrl)) {
                return false;
            }
            
            String domain = storageConfig.getLocal().getDomain();
            String accessPath = storageConfig.getLocal().getAccessPath();
            String storagePath = storageConfig.getLocal().getStoragePath();
            
            String relativePath;
            
            // 如果是完整URL，提取相对路径
            if (StringUtils.hasText(domain) && fileUrl.startsWith(domain)) {
                relativePath = fileUrl.substring(domain.length());
                if (relativePath.startsWith("/")) {
                    relativePath = relativePath.substring(1);
                }
            } else {
                relativePath = fileUrl;
                if (relativePath.startsWith("/")) {
                    relativePath = relativePath.substring(1);
                }
            }
            
            // 如果包含访问路径前缀，则移除
            if (relativePath.startsWith(accessPath)) {
                relativePath = relativePath.substring(accessPath.length());
                if (relativePath.startsWith("/")) {
                    relativePath = relativePath.substring(1);
                }
            }
            
            // 拼接实际存储路径
            String fullPath = storagePath + File.separator + relativePath;
            Path path = Paths.get(fullPath);
            
            if (Files.exists(path)) {
                Files.delete(path);
                return true;
            }
            
            return false;
        }
        
        @Override
        public String getType() {
            return StorageType.LOCAL.getCode();
        }
    }
} 